home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Text / WASTE 1.3a6 / Demo / Source / WEDemoMenus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-01  |  24.5 KB  |  1,190 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Menu Handling
  4.  
  5.     Copyright © 1993-1997 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11. #ifndef __ALIASES__
  12. #include <Aliases.h>
  13. #endif
  14.  
  15. #ifndef __DEVICES__
  16. #include <Devices.h>
  17. #endif
  18.  
  19. #ifndef __ERRORS__
  20. #include <Errors.h>
  21. #endif
  22.  
  23. #ifndef __LOWMEM__
  24. #include <LowMem.h>
  25. #endif
  26.  
  27. #ifndef __STANDARDFILE__
  28. #include <StandardFile.h>
  29. #endif
  30.  
  31. #ifndef __FILETYPESANDCREATORS__
  32. #include <FileTypesAndCreators.h>
  33. #endif
  34.  
  35. #ifndef __TOOLUTILS__
  36. #include <ToolUtils.h>
  37. #endif
  38.  
  39. #ifndef __WEDEMOAPP__
  40. #include "WEDemoIntf.h"
  41. #endif
  42.  
  43. #include "WETabs.h"
  44.  
  45. // resource types
  46.  
  47. #define kTypeMenuColorTable        'mctb'
  48.  
  49. // static variables
  50.  
  51. static Handle sColors ;        // handle to the 'mctb' resource for the Color menu
  52.  
  53. // constants used by DoClose()
  54.  
  55. enum {
  56.     kButtonSave            = 1,
  57.     kButtonCancel,
  58.     kButtonDontSave
  59. };
  60.  
  61. void SetDefaultDirectory ( const FSSpec * spec )
  62. {
  63.     LMSetCurDirStore ( spec -> parID ) ;
  64.     LMSetSFSaveDisk ( - spec -> vRefNum ) ;
  65. }
  66.  
  67. static pascal Boolean MySFDialogFilter( DialogRef dialog, EventRecord *event, SInt16 *item, void *yourData )
  68. {
  69. #pragma unused ( item, yourData )
  70.  
  71.     //     intercept window events directed to windows behind the dialog
  72.     if ( ( event->what == updateEvt ) || ( event->what == activateEvt ) )
  73.     {
  74.         if ( (WindowRef) event->message != GetDialogWindow( dialog ) )
  75.         {
  76.             DoWindowEvent( event );
  77.         }
  78.     }
  79.  
  80.     return false;
  81. }
  82.  
  83. static ModalFilterYDUPP GetMySFDialogFilter( void )
  84. {
  85. #ifdef __cplusplus
  86.     static ModalFilterYDUPP sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  87. #else
  88.     static ModalFilterYDUPP sFilterUPP = nil;
  89.     if ( sFilterUPP == nil )
  90.     {
  91.         sFilterUPP = NewModalFilterYDProc( MySFDialogFilter );
  92.     }
  93. #endif
  94.  
  95.     return sFilterUPP;
  96. }
  97.  
  98. SInt16    FindMenuItemText( MenuRef menu, ConstStr255Param stringToFind )
  99. {
  100.     SInt16        item;
  101.     Str255        itemString;
  102.  
  103.     for ( item = CountMenuItems( menu ); item >= 1; item-- )
  104.     {
  105.         GetMenuItemText( menu, item, itemString );
  106.         if ( EqualString( itemString, stringToFind, false, false ) )
  107.             break;
  108.     }
  109.  
  110.     return item;
  111. }
  112.  
  113. Boolean    EqualColor( const RGBColor *rgb1, const RGBColor *rgb2 )
  114. {
  115.     return ( (rgb1->red == rgb2->red) && (rgb1->green == rgb2->green) && (rgb1->blue == rgb2->blue) );
  116. }
  117.  
  118.  
  119. void PrepareMenus ( void )
  120. {
  121.     WindowRef        window;
  122.     WEReference        we;
  123.     MenuRef            menu;
  124.     MenuCRsrcPtr    pColors;
  125.     SInt16            item;
  126.     Str255            itemText;
  127.     SInt32            selStart, selEnd;
  128.     SInt32            threshold;
  129.     WEActionKind    actionKind;
  130.     WEStyleMode        mode;
  131.     TextStyle        ts;
  132.     Boolean            temp;
  133.  
  134.     // get a pointer to the frontmost window, if any
  135.  
  136.     window = FrontWindow ( ) ;
  137.  
  138.     // get associated WE instance
  139.  
  140.     we = ( window != nil ) ? GetWindowWE ( window ) : nil ;
  141.  
  142.     // *** FILE MENU ***
  143.  
  144.     menu = GetMenuHandle ( kMenuFile ) ;
  145.  
  146.     // first disable all items
  147.  
  148.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  149.     {
  150.         DisableItem ( menu, item ) ;
  151.     }
  152.  
  153.     // New, Open, and Quit are always enabled
  154.  
  155.     EnableItem ( menu, kItemNew ) ;
  156.     EnableItem ( menu, kItemOpen ) ;
  157.     EnableItem ( menu, kItemQuit ) ;
  158.  
  159.     // enable Close and Save As if there is an active window
  160.  
  161.     if ( window != nil )
  162.     {
  163.         EnableItem ( menu, kItemClose ) ;
  164.         EnableItem ( menu, kItemSaveAs ) ;
  165.  
  166.         // enable Save is the active window is dirty
  167.  
  168.         if ( WEGetModCount ( we ) > 0 )
  169.         {
  170.             EnableItem ( menu, kItemSave ) ;
  171.         }
  172.     }
  173.  
  174.     // *** EDIT MENU ***
  175.  
  176.     menu = GetMenuHandle ( kMenuEdit ) ;
  177.  
  178.     // first, disable all items
  179.  
  180.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  181.     {
  182.         DisableItem ( menu, item ) ;
  183.     }
  184.  
  185.     // by default, the Undo menu item should read "Can't Undo"
  186.  
  187.     GetIndString ( itemText, kUndoStringsID, 1 ) ;
  188.     SetMenuItemText ( menu, kItemUndo, itemText ) ;
  189.  
  190.     if ( window != nil )
  191.     {
  192.         // enable Paste if there's anything pasteable on the Clipboard
  193.  
  194.         if ( WECanPaste ( we ) )
  195.         {
  196.             EnableItem ( menu, kItemPaste ) ;
  197.         }
  198.  
  199.         // enable Undo if anything can be undone
  200.  
  201.         actionKind = WEGetUndoInfo ( & temp, we ) ;
  202.  
  203.         if ( actionKind != weAKNone )
  204.         {
  205.             EnableItem ( menu, kItemUndo ) ;
  206.  
  207.             // change the Undo menu item to "Undo/Redo" + name of action to undo/redo
  208.  
  209.             GetIndString ( itemText, kUndoStringsID, 2 * actionKind + temp ) ;
  210.             SetMenuItemText ( menu, kItemUndo, itemText ) ;
  211.         }
  212.  
  213.         // enable Select All if there is anything to select
  214.  
  215.         if ( WEGetTextLength ( we ) > 0 )
  216.         {
  217.             EnableItem ( menu, kItemSelectAll ) ;
  218.         }
  219.  
  220.         // get the current selection range
  221.  
  222.         WEGetSelection ( & selStart, & selEnd, we ) ;
  223.         if ( selStart != selEnd )
  224.         {
  225.             // enable Cut, Copy, and Clear if the selection range is not empty
  226.  
  227.             EnableItem ( menu, kItemCut ) ;
  228.             EnableItem ( menu, kItemCopy ) ;
  229.             EnableItem ( menu, kItemClear ) ;
  230.         }
  231.  
  232.         // determine which style attributes are continuous over the current selection range
  233.         // we'll need this information in order to check the Font/Size/Style/Color menus properly
  234.  
  235.         mode = weDoAll ;    // query about all attributes
  236.         WEContinuousStyle ( & mode, & ts, we ) ;
  237.     }
  238.     else
  239.     {
  240.         mode = 0 ;          // no window, so check no items
  241.     }
  242.  
  243.     // *** FONT MENU ***
  244.  
  245.     menu = GetMenuHandle ( kMenuFont ) ;
  246.  
  247.     // first, remove all check marks
  248.  
  249.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  250.     {
  251.         CheckItem ( menu, item, false ) ;
  252.     }
  253.  
  254.     // if there is a continuous font all over the selection range, check the
  255.     // corresponding menu item
  256.  
  257.     if ( mode & weDoFont )
  258.     {
  259.         GetFontName ( ts . tsFont, itemText ) ;
  260.         CheckItem ( menu, FindMenuItemText ( menu, itemText ), true ) ;
  261.     }
  262.  
  263.     // *** SIZE MENU ***
  264.  
  265.     menu = GetMenuHandle( kMenuSize );
  266.  
  267.     // first, remove all check marks
  268.  
  269.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  270.     {
  271.         CheckItem ( menu, item, false ) ;
  272.     }
  273.  
  274.     // if there is a continuous font size all over the selection range
  275.     // check the corresponding menu item
  276.  
  277.     if ( mode & weDoSize )
  278.     {
  279.         NumToString ( ts . tsSize, itemText ) ;
  280.         CheckItem ( menu, FindMenuItemText ( menu, itemText ), true ) ;
  281.     }
  282.  
  283.     // *** STYLE MENU ***
  284.  
  285.     menu = GetMenuHandle ( kMenuStyle ) ;
  286.  
  287.     // first, remove all check marks
  288.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  289.     {
  290.         CheckItem ( menu, item, false ) ;
  291.     }
  292.  
  293.     // check the style menu items corresponding to style attributes
  294.     if ( mode & weDoFace )
  295.     {
  296.         if ( ts.tsFace == normal )
  297.         {
  298.             CheckItem( menu, kItemPlainText, true );
  299.         }
  300.  
  301.         for ( item = kItemBold; item <= kItemExtended; item ++ )
  302.         {
  303.             if (ts.tsFace & ( 1 << ( item - kItemBold ) ) )
  304.             {
  305.                 CheckItem( menu, item, true );
  306.             }
  307.         }
  308.     }
  309.  
  310.     // *** COLOR MENU ***
  311.  
  312.     menu = GetMenuHandle ( kMenuColor ) ;
  313.  
  314.     // first, remove all check marks
  315.  
  316.     for ( item = CountMenuItems ( menu ) ; item >= 1; item -- )
  317.     {
  318.         CheckItem ( menu, item, false ) ;
  319.     }
  320.  
  321.     // if there is a continuous color all over the selection range,
  322.     // check the corresponding menu item (if any )
  323.  
  324.     if ( mode & weDoColor )
  325.     {
  326.         pColors = * ( MenuCRsrcHandle ) sColors ;
  327.         for ( item = pColors -> numEntries - 1 ; item >= 0 ; item -- )
  328.         {
  329.             if ( EqualColor ( & ts.tsColor, & pColors -> mcEntryRecs [ item ] . mctRGB2 ) )
  330.             {
  331.                 CheckItem ( menu, pColors -> mcEntryRecs [ item ] . mctItem, true ) ;
  332.             }
  333.  
  334.         } // end for loop
  335.     }
  336.  
  337.     // *** FEATURES MENU ***
  338.  
  339.     menu = GetMenuHandle( kMenuFeatures );
  340.  
  341.     // first remove all check marks
  342.     // (except the first two items, which have submenus!)
  343.  
  344.     for ( item = CountMenuItems ( menu ) ; item >= 3 ; item -- )
  345.     {
  346.         CheckItem ( menu, item, false ) ;
  347.     }
  348.  
  349.     if ( window != nil )
  350.     {
  351.         // mark each item according to the corresponding feature
  352.  
  353.         if ( WEIsTabHooks ( we ) )
  354.         {
  355.             CheckItem ( menu, kItemTabHooks, true ) ;
  356.             DisableItem ( menu, kItemAlignment ) ;
  357.             DisableItem ( menu, kItemDirection ) ;
  358.         }
  359.         else
  360.         {
  361.             EnableItem ( menu, kItemAlignment ) ;
  362.             EnableItem ( menu, kItemDirection ) ;
  363.         }
  364.  
  365.         if ( WEFeatureFlag ( weFAutoScroll, weBitTest, we ) )
  366.         {
  367.             CheckItem ( menu, kItemAutoScroll, true ) ;
  368.         }
  369.  
  370.          if ( WEFeatureFlag ( weFOutlineHilite, weBitTest, we ) )
  371.          {
  372.             CheckItem ( menu, kItemOutlineHilite, true ) ;
  373.         }
  374.  
  375.         if ( WEFeatureFlag( weFReadOnly, weBitTest, we ))
  376.         {
  377.             CheckItem ( menu, kItemReadOnly, true ) ;
  378.         }
  379.  
  380.         if ( WEFeatureFlag ( weFIntCutAndPaste, weBitTest, we ) )
  381.         {
  382.             CheckItem ( menu, kItemIntCutAndPaste, true ) ;
  383.         }
  384.  
  385.         if ( WEFeatureFlag( weFDragAndDrop, weBitTest, we ))
  386.         {
  387.             CheckItem ( menu, kItemDragAndDrop, true ) ;
  388.         }
  389.  
  390.         if ( ( WEGetInfo ( weTranslucencyThreshold, & threshold, we ) == noErr ) && ( threshold > 0 ) )
  391.         {
  392.             CheckItem ( menu, kItemTranslucentDrags, true ) ;
  393.         }
  394.  
  395.         if ( WEFeatureFlag( weFDrawOffscreen, weBitTest, we ) )
  396.         {
  397.             CheckItem ( menu, kItemOffscreenDrawing, true ) ;
  398.         }
  399.     }
  400.  
  401.     // *** ALIGNMENT MENU ***
  402.  
  403.     menu = GetMenuHandle ( kMenuAlignment ) ;
  404.  
  405.     // first, remove all check marks
  406.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  407.     {
  408.         CheckItem ( menu, item, false ) ;
  409.     }
  410.  
  411.     if ( window != nil )
  412.     {
  413.         // find the Aligment menu item corresponding to the current alignment
  414.         switch ( WEGetAlignment ( we ) )
  415.         {
  416.             case weFlushLeft:
  417.                 item = kItemAlignLeft ;
  418.                 break ;
  419.  
  420.             case weFlushRight:
  421.                 item = kItemAlignRight ;
  422.                 break ;
  423.  
  424.             case weFlushDefault:
  425.                 item = kItemAlignDefault ;
  426.                 break ;
  427.  
  428.             case weCenter:
  429.                 item = kItemCenter ;
  430.                 break ;
  431.  
  432.             case weJustify:
  433.                 item = kItemJustify ;
  434.                 break ;
  435.         }
  436.  
  437.         // check the menu item
  438.         CheckItem ( menu, item, true ) ;
  439.     }
  440.  
  441.     // *** DIRECTION MENU ***
  442.  
  443.     menu = GetMenuHandle ( kMenuDirection ) ;
  444.  
  445.     // first, remove all check marks
  446.     for ( item = CountMenuItems ( menu ) ; item >= 1 ; item -- )
  447.     {
  448.         CheckItem ( menu, item, false ) ;
  449.     }
  450.  
  451.     if ( window != nil )
  452.     {
  453.         // find the Direction menu item corresponding to the current direction
  454.         switch ( WEGetDirection ( we ) )
  455.         {
  456.             case weDirDefault:
  457.                 item = kItemDirectionDefault ;
  458.                 break ;
  459.  
  460.             case weDirLeftToRight:
  461.                 item = kItemDirectionLR ;
  462.                 break ;
  463.  
  464.             case weDirRightToLeft:
  465.                 item = kItemDirectionRL ;
  466.                 break ;
  467.         }
  468.  
  469.         // check the menu item
  470.         CheckItem ( menu, item, true ) ;
  471.     }
  472. }
  473.  
  474. void DoDeskAcc ( SInt16 menuItem )
  475. {
  476.     Str255 deskAccessoryName ;
  477.  
  478.     GetMenuItemText ( GetMenuHandle ( kMenuApple ), menuItem, deskAccessoryName ) ;
  479.     OpenDeskAcc ( deskAccessoryName ) ;
  480. }
  481.  
  482. OSErr DoNew( void )
  483. {
  484.     // create a new window from scratch
  485.     return CreateWindow( nil );
  486. }
  487.  
  488. OSErr DoOpen( void )
  489. {
  490.     StandardFileReply        reply;
  491.     SFTypeList                typeList;
  492.     OSErr                    err = noErr;
  493.     Point                    where = { -1, -1 };  // auto center dialog
  494.  
  495.     // set up a list of file types we can open for StandardGetFile
  496.     typeList[0] = kTypeText;
  497.     typeList[1] = ftSimpleTextDocument;
  498.  
  499.     // put up the standard open dialog box.
  500.     // (we use CustomGetFile instead of StandardGetFile because we want to provide
  501.     // our own dialog filter procedure that takes care of updating our windows)
  502.     CustomGetFile( nil, 2, typeList, &reply, 0, where, nil, GetMySFDialogFilter( ), nil, nil, nil );
  503.  
  504.     // if the user ok'ed the dialog, create a new window from the specified file
  505.     if ( reply.sfGood )
  506.         err = CreateWindow( &reply.sfFile );
  507.     else
  508.         err = userCanceledErr;
  509.  
  510.     return err;
  511. }
  512.  
  513. OSErr SaveWindow( const FSSpec *pFileSpec, WindowRef window )
  514. {
  515.     DocumentHandle    hDocument;
  516.     AliasHandle        alias = nil;
  517.     OSErr            err;
  518.  
  519.     hDocument = GetWindowDocument(window);
  520.     ForgetHandle( & (*hDocument)->fileAlias );
  521.  
  522.     // save the text
  523.  
  524.     if ( ( err = WriteTextFile( pFileSpec, (*hDocument)->we ) ) == noErr )
  525.     {
  526.         SetWTitle( window, pFileSpec->name );
  527.  
  528.         // replace the old window alias (if any) with a new one created from pFileSpec
  529.         NewAlias( nil, pFileSpec, &alias );
  530.  
  531.         // if err, alias will be nil, and it's not fatal, just will make subsequent saves annoying
  532.         (* hDocument)->fileAlias = (Handle) alias;
  533.     }
  534.  
  535.     return err;
  536. }
  537.  
  538.  
  539. OSErr    DoSaveAs( const FSSpec *suggestedTarget, WindowRef window )
  540. {
  541.     StringHandle        hPrompt;
  542.     Str255                defaultName;
  543.     StandardFileReply    reply;
  544.     Point                where = { -1, -1 }; // autocenter's dialog
  545.     OSErr                err;
  546.  
  547.     // get the prompt string for CustomPutFile from a string resource and lock it
  548.     hPrompt = GetString( kPromptStringID );
  549.     HLockHi( (Handle) hPrompt );
  550.  
  551.     // if a suggested target file is provided, use its name as the default name
  552.     if ( suggestedTarget != nil )
  553.     {
  554.         PStringCopy( suggestedTarget->name, defaultName );
  555.         SetDefaultDirectory( suggestedTarget );
  556.     }
  557.     else
  558.     {
  559.         // otherwise use the window title as default name for CustomPutFile
  560.         GetWTitle( window, defaultName );
  561.     }
  562.  
  563.     // put up the standard Save dialog box
  564.     CustomPutFile( *hPrompt, defaultName, &reply, 0, where, nil, GetMySFDialogFilter(), nil, nil, nil );
  565.  
  566.     // unlock the string resource
  567.     HUnlock( (Handle)hPrompt );
  568.  
  569.     // if the user ok'ed the dialog, save the window to the specified file
  570.     if ( reply.sfGood )
  571.         err = SaveWindow( &reply.sfFile, window );
  572.     else
  573.         err = userCanceledErr;
  574.  
  575.     return err;
  576. }
  577.  
  578. OSErr    DoSave( WindowRef window )
  579. {
  580.     FSSpec        spec;
  581.     FSSpecPtr    suggestedTarget = nil;
  582.     Boolean        promptForNewFile = true;
  583.     Boolean        aliasTargetWasChanged;
  584.     OSErr        err;
  585.  
  586.     // resolve the alias associated with this window, if any
  587.  
  588.     if ( (* GetWindowDocument(window) )->fileAlias != nil )
  589.     {
  590.         if ( ( ResolveAlias( nil, (AliasHandle) (* GetWindowDocument(window))->fileAlias, &spec, &aliasTargetWasChanged ) == noErr ) )
  591.         {
  592.             if ( aliasTargetWasChanged )
  593.                 suggestedTarget = &spec;
  594.             else
  595.                 promptForNewFile = false;
  596.         }
  597.     }
  598.  
  599.     // if no file has been previously associated with this window, or if the
  600.     // alias resolution has failed, or if the alias target was changed
  601.     // prompt the user for a new destination
  602.  
  603.     if ( promptForNewFile )
  604.         err = DoSaveAs( suggestedTarget, window );
  605.     else
  606.         err = SaveWindow( &spec, window );
  607.  
  608.     return err;
  609. }
  610.  
  611. static pascal Boolean SaveChangesDialogFilter( DialogRef dialog, EventRecord *event, SInt16 *item )
  612. {
  613.     //    map command + D to the "Don't Save" button
  614.     if ( ( event->what == keyDown ) && ( event->modifiers & cmdKey ) && ( ( event->message & charCodeMask ) == 'd' ) )
  615.     {
  616.         //    flash the button briefly
  617.         FlashButton( dialog, kButtonDontSave );
  618.  
  619.         //    fake an event in the button
  620.         *item = kButtonDontSave;
  621.         return true;
  622.     }
  623.  
  624.     //    route everything else to our default handler
  625.     return CallModalFilterProc( GetMyStandardDialogFilter( ), dialog, event, item );
  626. }
  627.  
  628. OSErr DoClose( ClosingOption closing, SavingOption saving, WindowRef window )
  629. {
  630.     Str255        s1, s2;
  631.     SInt16        alertResult;
  632.     OSErr        err;
  633. #ifdef __cplusplus
  634.     static ModalFilterUPP sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  635. #else
  636.     static ModalFilterUPP sFilterProc = nil;
  637.     if ( sFilterProc == nil )
  638.     {
  639.         sFilterProc = NewModalFilterProc( SaveChangesDialogFilter );
  640.     }
  641. #endif
  642.  
  643.     // is this window dirty?
  644.     if ( WEGetModCount( GetWindowWE(window) ) > 0 )
  645.     {
  646.         // do we have to ask the user whether to save changes?
  647.  
  648.         if ( saving == savingAsk )
  649.         {
  650.             // prepare the parametric strings to be used in the Save Changes alert box
  651.  
  652.             GetWTitle( window, s1 );
  653.  
  654.             GetIndString( s2, kClosingQuittingStringsID, 1 + closing );
  655.             ParamText( s1, s2, nil, nil );
  656.  
  657.             // put up the Save Changes? alert box
  658.  
  659.             SetCursor( &qd.arrow );
  660.  
  661.             alertResult = Alert( kAlertSaveChanges, sFilterProc );
  662.  
  663.             // exit if the user canceled the alert box
  664.  
  665.             if ( alertResult == kButtonCancel )
  666.                 return userCanceledErr;
  667.  
  668.             if ( alertResult == kButtonSave )
  669.                 saving = savingYes;
  670.             else
  671.                 saving = savingNo;
  672.         }
  673.  
  674.         if ( saving == savingYes )
  675.         {
  676.             if ( ( err = DoSave( window ) ) != noErr )
  677.                 return err;
  678.         }
  679.     }
  680.  
  681.     // destroy the window
  682.     DestroyWindow( window );
  683.  
  684.     return noErr;
  685. }
  686.  
  687. OSErr DoQuit( SavingOption saving )
  688. {
  689.     WindowRef window;
  690.     OSErr err;
  691.  
  692.     // close all windows
  693.     do
  694.     {
  695.         if ( ( window = FrontWindow( ) ) != nil )
  696.         {
  697.             if ( ( err = DoClose( closingApplication, saving, window ) ) != noErr )
  698.                 return err;
  699.         }
  700.     } while ( window != nil );
  701.  
  702.     // set a flag so we drop out of the event loop
  703.     gExiting = true;
  704.  
  705.     return noErr;
  706. }
  707.  
  708. void DoAppleChoice( SInt16 menuItem )
  709. {
  710.     if ( menuItem == kItemAbout )
  711.         DoAboutBox( kDialogAboutBox );
  712.     else
  713.         DoDeskAcc( menuItem );
  714. }
  715.  
  716. void DoFileChoice( SInt16 menuItem )
  717. {
  718.     WindowRef window = FrontWindow();
  719.  
  720.     switch( menuItem )
  721.     {
  722.         case kItemNew:
  723.             DoNew( );
  724.             break;
  725.  
  726.         case kItemOpen:
  727.             DoOpen( );
  728.             break;
  729.  
  730.         case kItemClose:
  731.             DoClose( closingWindow, savingAsk, window );
  732.             break;
  733.  
  734.         case kItemSave:
  735.             DoSave( window );
  736.             break;
  737.  
  738.         case kItemSaveAs:
  739.             DoSaveAs( nil, window );
  740.             break;
  741.  
  742.         case kItemQuit:
  743.             DoQuit( savingAsk );
  744.             break;
  745.     }
  746. }
  747.  
  748. void DoEditChoice ( SInt16 menuItem )
  749. {
  750.     WindowRef window ;
  751.     WEReference we ;
  752.  
  753.     // do nothing is no window is active
  754.     if ( ( window = FrontWindow ( ) ) == nil )
  755.     {
  756.         return ;
  757.     }
  758.  
  759.     we = GetWindowWE ( window ) ;
  760.  
  761.     switch ( menuItem )
  762.     {
  763.         case kItemUndo:
  764.              WEUndo ( we ) ;
  765.             break ;
  766.  
  767.         case kItemCut :
  768.             WECut ( we ) ;
  769.             break ;
  770.  
  771.         case kItemCopy:
  772.             WECopy ( we ) ;
  773.             break ;
  774.  
  775.         case kItemPaste:
  776.             WEPaste ( we ) ;
  777.             break ;
  778.  
  779.         case kItemClear:
  780.             WEDelete ( we ) ;
  781.             break ;
  782.  
  783.         case kItemSelectAll:
  784.             WESetSelection ( 0, LONG_MAX, we ) ;
  785.             break ;
  786.     }
  787. }
  788.  
  789. void DoFontChoice ( SInt16 menuItem, EventModifiers modifiers )
  790. {
  791.     WindowRef        window;
  792.     Str255            fontName;
  793.     WEStyleMode        mode;
  794.     TextStyle        ts;
  795.  
  796.     //    do nothing if there is no front window
  797.     if ( ( window = FrontWindow ( ) ) == nil )
  798.     {
  799.         return ;
  800.     }
  801.  
  802.     GetMenuItemText ( GetMenuHandle ( kMenuFont ), menuItem, fontName ) ;
  803.     GetFNum ( fontName, & ts . tsFont ) ;
  804.  
  805.     //    use script-preserving mode by default (see WASTE docs)
  806.     //    force font change across the whole selection if the option key was held down
  807.     mode = ( modifiers & optionKey ) ? weDoFont : ( weDoFont + weDoPreserveScript + weDoExtractSubscript ) ;
  808.  
  809.     //    set the font of the selection
  810.     WESetStyle ( mode, & ts, GetWindowWE ( window ) ) ;
  811. }
  812.  
  813. void DoSizeChoice ( SInt16 menuItem )
  814. {
  815.     WindowRef        window;
  816.     Str255            sizeString;
  817.     SInt32            size;
  818.     WEStyleMode        mode;
  819.     TextStyle        ts;
  820.  
  821.     //    do nothing if there is no front window
  822.     if ( ( window = FrontWindow ( ) ) == nil )
  823.     {
  824.         return ;
  825.     }
  826.  
  827.     if ( menuItem <= kItemLastSize )
  828.     {
  829.         GetMenuItemText ( GetMenuHandle ( kMenuSize ), menuItem, sizeString ) ;
  830.         StringToNum ( sizeString, & size ) ;
  831.         ts . tsSize = size ;
  832.         mode = weDoSize ;
  833.     }
  834.     else if ( menuItem == kItemSmaller )
  835.     {
  836.         ts . tsSize = - 1 ;
  837.         mode = weDoAddSize ;
  838.     }
  839.     else if ( menuItem == kItemLarger )
  840.     {
  841.         ts . tsSize = + 1 ;
  842.         mode = weDoAddSize ;
  843.     }
  844. /*
  845.     else if ( menuItem == kItemOtherSize )
  846.     {
  847.         //    get current selection size (if continuous)
  848.         ts . tsSize = 12 ;
  849.         mode = weDoSize ;
  850.         WEContinuousStyle ( & mode, & ts, GetWindowWE ( window ) ) ;
  851.  
  852.         //    let the user choose any size via the Font Size picker
  853.         if ( DoSizeDialog ( & ts . tsSize ) != noErr )
  854.         {
  855.             return ;
  856.         }
  857.         mode = weDoSize ;
  858.     }
  859. */
  860.     else
  861.     {
  862.         return ;
  863.     }
  864.  
  865.     //    set the size of the selection
  866.     WESetStyle ( mode, & ts, GetWindowWE ( window ) ) ;
  867. }
  868.  
  869. void DoStyleChoice ( SInt16 menuItem )
  870. {
  871.     WindowRef         window ;
  872.     TextStyle         ts ;
  873.  
  874.     //    do nothing if there is no front window
  875.     if ( ( window = FrontWindow ( ) ) == nil )
  876.     {
  877.         return ;
  878.     }
  879.  
  880.     if ( menuItem == kItemPlainText )
  881.     {
  882.         ts . tsFace = normal ;
  883.     }
  884.     else
  885.     {
  886.         ts . tsFace = 1 << ( menuItem - kItemBold ) ;
  887.     }
  888.  
  889.     //    set the style of the selection
  890.     WESetStyle ( weDoFace + weDoToggleFace, & ts, GetWindowWE ( window ) ) ;
  891. }
  892.  
  893. void DoColorChoice ( SInt16 menuItem )
  894. {
  895.     WindowRef             window ;
  896.     MenuCRsrcPtr         pColors ;
  897.     SInt16                 i ;
  898.     TextStyle            ts ;
  899.  
  900.     // do nothing if there is no front window
  901.     if ( ( window = FrontWindow( ) ) == nil )
  902.     {
  903.         return ;
  904.     }
  905.  
  906.     if ( menuItem <= kItemLastColor )
  907.     {
  908.         // find the color corresponding to the chosen menu item
  909.         pColors = * ( MenuCRsrcHandle ) sColors ;
  910.         for ( i = pColors -> numEntries - 1 ; i >= 0 ; i -- )
  911.         {
  912.             if ( pColors -> mcEntryRecs [ i ] . mctItem == menuItem )
  913.             {
  914.                 ts . tsColor = pColors -> mcEntryRecs [ i ] . mctRGB2 ;
  915.                 break ;
  916.             }
  917.         }
  918.     }
  919. /*
  920.     else if ( menuItem == kItemOtherColor )
  921.     {
  922.         //    get current selection color (if continuous)
  923.         WEStyleMode mode = weDoColor ;
  924.  
  925.         ts . tsColor . red = 0 ;
  926.         ts . tsColor . green = 0 ;
  927.         ts . tsColor . blue = 0 ;
  928.         WEContinuousStyle ( & mode, & ts, GetWindowWE ( window ) ) ;
  929.  
  930.         //    let the user choose any color via the Color picker
  931.         if ( DoColorDialog ( & ts . tsColor ) != noErr )
  932.         {
  933.             return ;
  934.         }
  935.     }
  936. */
  937.     else
  938.     {
  939.         return ;
  940.     }
  941.  
  942.     //    set the color of the selection
  943.     WESetStyle ( weDoColor, & ts, GetWindowWE ( window ) ) ;
  944. }
  945.  
  946. void DoAlignmentChoice ( SInt16 menuItem )
  947. {
  948.     WindowRef window ;
  949.     WEAlignment alignment ;
  950.  
  951.     if ( ( window = FrontWindow( ) ) == nil )
  952.     {
  953.         return ;
  954.     }
  955.  
  956.     switch( menuItem )
  957.     {
  958.         case kItemAlignDefault:
  959.             alignment = weFlushDefault ;
  960.             break ;
  961.  
  962.         case kItemAlignLeft:
  963.             alignment = weFlushLeft ;
  964.             break ;
  965.  
  966.         case kItemCenter:
  967.             alignment = weCenter ;
  968.             break ;
  969.  
  970.         case kItemAlignRight:
  971.             alignment = weFlushRight ;
  972.             break ;
  973.  
  974.         case kItemJustify:
  975.             alignment = weJustify ;
  976.             break ;
  977.     }
  978.  
  979.     // set the alignment mode (this automatically redraws the text)
  980.     WESetAlignment ( alignment, GetWindowWE ( window ) ) ;
  981. }
  982.  
  983. void DoDirectionChoice ( SInt16 menuItem )
  984. {
  985.     WindowRef window;
  986.     WEDirection direction;
  987.  
  988.     if ( ( window = FrontWindow ( ) ) == nil )
  989.     {
  990.         return ;
  991.     }
  992.  
  993.     switch ( menuItem )
  994.     {
  995.         case kItemDirectionDefault:
  996.             direction = weDirDefault ;
  997.             break ;
  998.  
  999.         case kItemDirectionLR:
  1000.             direction = weDirLeftToRight ;
  1001.             break ;
  1002.  
  1003.         case kItemDirectionRL:
  1004.             direction = weDirRightToLeft ;
  1005.             break ;
  1006.     }
  1007.  
  1008.     // set the primary line direction (this automatically redraws the text)
  1009.     WESetDirection ( direction, GetWindowWE ( window ) ) ;
  1010. }
  1011.  
  1012. void DoFeatureChoice ( SInt16 menuItem )
  1013. {
  1014.     WindowRef window ;
  1015.     WEReference we ;
  1016.     SInt32 threshold ;
  1017.  
  1018.     if ( ( window = FrontWindow ( ) ) == nil )
  1019.         return ;
  1020.  
  1021.     we = GetWindowWE ( window ) ;
  1022.  
  1023.     if ( menuItem == kItemTabHooks )
  1024.     {
  1025.         // install or remove our custom tab hooks
  1026.  
  1027.         if ( ! WEIsTabHooks ( we ) )
  1028.         {
  1029.             // left-align the text (the hooks only work with left-aligned text )
  1030.             WESetAlignment ( weFlushLeft, we ) ;
  1031.  
  1032.             // force a LR primary direction
  1033.             // (the hooks don't work with bidirectional text anyway)
  1034.             WESetDirection ( weDirLeftToRight, we ) ;
  1035.  
  1036.             // install tab hooks
  1037.             WEInstallTabHooks ( we ) ;
  1038.         }
  1039.         else
  1040.         {
  1041.             // remove tab hooks
  1042.             WERemoveTabHooks ( we ) ;
  1043.         }
  1044.  
  1045.         // turn the cursor into a wristwatch
  1046.         SetCursor ( * GetCursor ( watchCursor ) ) ;
  1047.  
  1048.         // recalculate link breaks and redraw the text
  1049.         WECalText ( we ) ;
  1050.         WEUpdate ( nil, we ) ;
  1051.     }
  1052.     else
  1053.     {
  1054.         switch ( menuItem )
  1055.         {
  1056.             case kItemAutoScroll:
  1057.                 WEFeatureFlag ( weFAutoScroll, weBitToggle, we ) ;
  1058.                 break;
  1059.  
  1060.             case kItemOutlineHilite:
  1061.                 WEFeatureFlag ( weFOutlineHilite, weBitToggle, we ) ;
  1062.                 break;
  1063.  
  1064.             case kItemReadOnly:
  1065.                 WEFeatureFlag ( weFReadOnly, weBitToggle, we ) ;
  1066.                 break;
  1067.  
  1068.             case kItemIntCutAndPaste:
  1069.                 WEFeatureFlag ( weFIntCutAndPaste, weBitToggle, we ) ;
  1070.                 break;
  1071.  
  1072.             case kItemDragAndDrop:
  1073.                 WEFeatureFlag ( weFDragAndDrop, weBitToggle, we ) ;
  1074.                 break;
  1075.  
  1076.             case kItemTranslucentDrags:
  1077.                 if ( WEGetInfo ( weTranslucencyThreshold, & threshold, we ) == noErr )
  1078.                 {
  1079.                     threshold = kStandardTranslucencyThreshold - threshold ;
  1080.                     WESetInfo ( weTranslucencyThreshold, & threshold, we ) ;
  1081.                 }
  1082.                 break;
  1083.  
  1084.             case kItemOffscreenDrawing:
  1085.                 WEFeatureFlag ( weFDrawOffscreen, weBitToggle, we ) ;
  1086.                 break;
  1087.         }
  1088.     }
  1089. }
  1090.  
  1091. void DoMenuChoice ( SInt32 menuChoice, EventModifiers modifiers )
  1092. {
  1093.     SInt16 menuID, menuItem ;
  1094.  
  1095.     // extract menu ID and menu item from menuChoice
  1096.  
  1097.     menuID = HiWord ( menuChoice ) ;
  1098.     menuItem = LoWord ( menuChoice ) ;
  1099.  
  1100.     // dispatch on menuID
  1101.  
  1102.     switch ( menuID )
  1103.     {
  1104.         case kMenuApple:
  1105.             DoAppleChoice ( menuItem ) ;
  1106.             break ;
  1107.  
  1108.         case kMenuFile:
  1109.             DoFileChoice ( menuItem ) ;
  1110.             break ;
  1111.  
  1112.         case kMenuEdit:
  1113.             DoEditChoice ( menuItem ) ;
  1114.             break ;
  1115.  
  1116.         case kMenuFont:
  1117.             DoFontChoice ( menuItem, modifiers ) ;
  1118.             break ;
  1119.  
  1120.         case kMenuSize:
  1121.             DoSizeChoice ( menuItem ) ;
  1122.             break ;
  1123.  
  1124.         case kMenuStyle:
  1125.             DoStyleChoice ( menuItem ) ;
  1126.             break ;
  1127.  
  1128.         case kMenuColor:
  1129.             DoColorChoice ( menuItem ) ;
  1130.             break ;
  1131.  
  1132.         case kMenuFeatures:
  1133.             DoFeatureChoice ( menuItem ) ;
  1134.             break ;
  1135.  
  1136.         case kMenuAlignment:
  1137.             DoAlignmentChoice ( menuItem ) ;
  1138.             break ;
  1139.  
  1140.         case kMenuDirection:
  1141.             DoDirectionChoice ( menuItem ) ;
  1142.             break ;
  1143.     }
  1144.  
  1145.     HiliteMenu ( 0 ) ;
  1146. }
  1147.  
  1148. OSErr InitializeMenus ( void )
  1149. {
  1150.     OSErr err = noErr ;
  1151.  
  1152.     // build up the whole menu bar from the 'MBAR' resource
  1153.     SetMenuBar ( GetNewMBar ( kMenuBarID ) ) ;
  1154.  
  1155.     // add names to the apple and Font menus
  1156.     AppendResMenu ( GetMenuHandle ( kMenuApple ), kTypeDeskAccessory ) ;
  1157.     AppendResMenu ( GetMenuHandle ( kMenuFont ), kTypeFont ) ;
  1158.  
  1159.     // insert the alignment and direction submenus into the hierarchical
  1160.     // portion of the menu list
  1161.     InsertMenu ( GetMenu ( kMenuAlignment ), -1 ) ;
  1162.     InsertMenu ( GetMenu ( kMenuDirection ), -1 ) ;
  1163.  
  1164.     // disable the "Drag and Drop Editing" item in the Features menu once and for all
  1165.     // if the Drag Manager isn't available
  1166.     if ( ! gHasDragAndDrop )
  1167.     {
  1168.         DisableItem ( GetMenuHandle ( kMenuFeatures ), kItemDragAndDrop ) ;
  1169.     }
  1170.  
  1171.     // disable the "Other" item in the Color menu if Color QuickDraw isn't available
  1172.     if ( ! gHasColorQD )
  1173.     {
  1174.         DisableItem ( GetMenuHandle ( kMenuColor ), kItemOtherColor ) ;
  1175.     }
  1176.  
  1177.     // load the menu color table for the color menu
  1178.     sColors = GetResource ( kTypeMenuColorTable, kMenuColor ) ;
  1179.     if ( ( err = ResError ( ) ) != noErr )
  1180.     {
  1181.         return err ;
  1182.     }
  1183.     HNoPurge ( sColors ) ;
  1184.  
  1185.     // draw the menu bar
  1186.     DrawMenuBar ( ) ;
  1187.  
  1188.     return err ;
  1189. }
  1190.